package at.ac.tuwien.semweb2;

import java.util.Iterator;
import java.util.List;

import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.InfModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.util.FileManager;

/**
 * This class is a bluepring of an object, which lists all Certifiable objects, which are to be trusted,
 * based on the rules described at <url>http://kill.devc.at/users/rho/courses/semweb/ws08/task2</url>,
 * SubTask B.
 * 
 * It depends on the Jena Framework and uses an ontology model and instance data, which can be
 * found in the file instances.ttl.
 * Furthermore, the listing is created upon reasoner rules, defined in the file trust.rules.
 * 
 * @authors P. Petrov, M. Maly
 *
 */
public class trust {

	/**
	 * This object represents an ontology in the Jena Framework. In this case
	 * it is a CA Ontology. Please refer to <url>http://kill.devc.at/users/rho/courses/semweb/ws08/task2</url>
	 * for more information.
	 */
	private OntModel onto;

	/**
	 * This is a object for the language specification used by the model.
	 */
	private OntModelSpec spec;

	/**
	 * This integer counts the Certifiable objects, which Hubert trusts.
	 */
	private static int trustCounter = 0;

	/**
	 * This String holds the tuwien/ca namespace.
	 */
	private static final String TUW_CA_NS = "http://tuwien.ac.at/lvs/ca#";
	
	/**
	 * This String holds the URI path to the ontology file.
	 */
	private static final String INSTANCES_URI = "file:instances.ttl";
	
	/**
	 * This String holds the URI path to the reasoner rules file.
	 */
	private static final String REASONER_RULES_URI = "file:trust.rules";
	
	/**
	 * This String defines the turtle notation, that is used for the ontology.
	 */
	private static final String TTL_NOTATION = "Turtle";

	/**
	 * This constructor sets the ontology model specification when creating the trust object. 
	 * @param spec
	 */
	public trust(OntModelSpec spec) {
		this.spec = spec;
	}

	/**
	 * This is the entry point of the program. It creates a trust object and
	 * initializes it with an <class>com.hp.hpl.jena.ontology.OntModelSpec.OWL_MEM_MICRO_RULE_INF</class>
	 * object, which is a specification for OWL models.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		trust t = new trust(OntModelSpec.OWL_MEM_MICRO_RULE_INF);
		t.createOntology();
		t.ruleReasoning();

	}

	/**
	 * This method creats an empty ontology object and fills it with
	 * the data based on the ca ontology.
	 *
	 */
	private void createOntology() {
		onto = ModelFactory.createOntologyModel(spec, null);
		onto.read(INSTANCES_URI, TTL_NOTATION);
	}

	/**
	 * This method lists all Certifiable objects, which are to be
	 * trusted by Hubert, based on reasoner rules. These can be
	 * found in the trust.rules file.
	 *
	 */
	private void ruleReasoning() {
		List rules = Rule.rulesFromURL(REASONER_RULES_URI);

		Reasoner reasoner = new GenericRuleReasoner(rules);
		Model instances = FileManager.get().loadModel(INSTANCES_URI);
		InfModel inf = ModelFactory.createInfModel(reasoner, instances);

		Resource r = instances.getResource(TUW_CA_NS + "Hubert");
		Property p = instances.getProperty(TUW_CA_NS, "trusts");
		Iterator list = inf.listStatements(r, p, (RDFNode) null);

		System.out.println("NS ca: => " + TUW_CA_NS);
		System.out.println("Hubert trusts these certifiables\n");
		while (list.hasNext()) {
			System.out.println(++trustCounter + " - "
					+ list.next().toString().replaceAll(TUW_CA_NS, "ca:"));
		}
		
		sparqlReasoning(inf);
		
	}
	
	/**
	 * This method uses sparql to filter all developers or developer organisation
	 * whom Hubert trusts.
	 * 
	 * @param model - InfModel A model object, which holds all certifiables whom Hubert trusts after the rule reasoning
	 */
	private void sparqlReasoning(InfModel model) {
		QueryExecution qe = QueryExecutionFactory.create (
                "SELECT ?trustedDeveloper "+
                "WHERE { "  +
                "<" + TUW_CA_NS +"Hubert> <" + TUW_CA_NS + "trusts> ?trustedDeveloper ." +
                "?trustedDeveloper <" + TUW_CA_NS + "holdsCertificate> ?certificate ." +
                "?certificate <" +TUW_CA_NS + "certificatePurpose>  <" + TUW_CA_NS + "developer> ." + 
                "}",
        model);
		
		trustCounter = 0;
		System.out.println("\nHubert trusts the following developers\n");
		for (ResultSet rs = qe.execSelect(); rs.hasNext(); ) {
		     QuerySolution binding = rs.nextSolution();
		     System.out.println(++trustCounter + " - [" + binding.get("trustedDeveloper").toString().replaceAll(TUW_CA_NS, "ca:")+"]");
		}
	}
}